package com.example.codegen.controller;

import cn.hutool.core.util.StrUtil;
import com.example.codegen.service.DatasourceService;
import com.example.codegen.vo.GeneratedBuilder;
import com.example.codegen.vo.GeneratedTable;
import com.example.codegen.vo.GenerationParam;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@RestController
@Slf4j
@RequestMapping("/template")
@Tag(name = "模板")
@Validated
public class TemplateController {

    private DatasourceService datasourceService;

    @Autowired
    public TemplateController(DatasourceService datasourceService) throws IOException {
        this.datasourceService = datasourceService;
    }

    @PostMapping("/generate")
    @Operation(summary = "代码生成")
    public String generateCode(@RequestBody GenerationParam param) throws Exception {
        StringTemplateLoader templateLoader = new StringTemplateLoader();
        Map<String, String> templateNameMap = new HashMap<>();
        String templatePath = param.getStrategy().getJavaTemplatePath();
        Resource[] javaTemplates = new PathMatchingResourcePatternResolver().getResources("classpath*:" + templatePath + "/**/*");
        for (Resource resource : javaTemplates) {
            if (resource.isFile() && !resource.isReadable()) {
                continue;
            }
            String filePath = URLDecoder.decode(resource.getURL().getPath(), StandardCharsets.UTF_8);
            Pattern pattern = Pattern.compile("^.+" + templatePath + "((.*)(/[^/]+))$");
            Matcher matcher = pattern.matcher(filePath);
            if (!matcher.find()) {
                continue;
            }
            String relativeFilePath = matcher.group(1);
            String key = RandomStringUtils.random(6, true, true);
            templateNameMap.put(key, relativeFilePath);
            templateLoader.putTemplate(key, resource.getContentAsString(StandardCharsets.UTF_8));
        }
        Configuration configuration = new Configuration(Configuration.getVersion());
        configuration.setTemplateLoader(templateLoader);

        GeneratedBuilder builder = new GeneratedBuilder(param.getStrategy(), param.getDatasource().getDatabaseDriver());
        for (String tableName : param.getTables()) {
            GeneratedTable generatedTable = builder.build(datasourceService.getTable(param.getDatasource(), tableName), datasourceService.getColumns(param.getDatasource(), tableName));
            for (Map.Entry<String, String> entry : templateNameMap.entrySet()) {
                Properties properties = new Properties();
                properties.put("modelName", generatedTable.getModelName());
                PropertyPlaceholderHelper placeholderHelper = new PropertyPlaceholderHelper("${", "}", null, false);
                File generateFile = new File(builder.getJavaGenerateDirectory(), StrUtil.removeSuffix(placeholderHelper.replacePlaceholders(entry.getValue(), properties), ".ftl"));
                if (!generateFile.getParentFile().exists()) {
                    generateFile.getParentFile().mkdirs();
                }
                Template template = configuration.getTemplate(entry.getKey());
                FileWriter writer = new FileWriter(generateFile, StandardCharsets.UTF_8);
                template.process(generatedTable, writer);
                writer.close();
            }
        }
        return "success";
    }
}
